package com.loooooo.pm2024.modules.pm.service;


import com.loooooo.pm2024.exception.MyBaseException;
import com.loooooo.pm2024.modules.pm.mapper.IssueMapper;
import com.loooooo.pm2024.modules.pm.mapper.TaskMapper;
import com.loooooo.pm2024.modules.pm.model.Issue;
import com.loooooo.pm2024.modules.pm.model.Task;
import com.loooooo.pm2024.modules.pm.model.TaskLog;
import com.loooooo.pm2024.modules.pm.model.WorkLog;
import com.loooooo.pm2024.modules.pm.selector.IssueSelector;
import com.loooooo.pm2024.modules.pm.selector.TaskLogSelector;
import com.loooooo.pm2024.modules.pm.selector.TaskSelector;
import com.loooooo.pm2024.modules.pm.selector.WorkLogSelector;
import com.loooooo.pm2024.modules.sys.model.PrettyUser;
import com.loooooo.pm2024.modules.sys.model.User;
import com.loooooo.pm2024.modules.sys.selector.UserSelector;
import com.loooooo.pm2024.modules.sys.service.UserService;
import com.loooooo.pm2024.security.SecurityUtils;
import com.loooooo.pm2024.service.IdService;
import com.loooooo.pm2024.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class TaskService {

    @Autowired
    TaskMapper taskMapper;
    @Autowired
    IdService idService;
    @Autowired
    TaskLogService taskLogService;
    @Autowired
    IssueService issueService;

    @Autowired
    TransactionTemplate transactionTemplate;
    @Autowired
    UserService userService;
    @Autowired
    WorkLogService workLogService;

    public Task get(Long id) {
        return get(id, null);
    }

    public Task get(Long id, TaskSelector selector) {
        Task task = taskMapper.get(id);
        if (task != null) {

            if (selector != null) {
                if (Objects.equals(1, selector.getWithLogList())) {
                    TaskLogSelector logSelector = new TaskLogSelector();
                    logSelector.getTarget().setTaskId(task.getId());
                    List<TaskLog> logList = taskLogService.list(logSelector);
                    task.setLogList(logList);
                }
            }
            if (task.getPlannedCompletionTime() != null && task.getPlannedCompletionTime() > 0) {
                long today = DateUtils.localDate2Long(LocalDate.now());
                int d = (int) ((task.getPlannedCompletionTime() - today) / (1000 * 3600 * 24) + 1);
                task.setDayRemaining(d);
            }
        }

        return task;
    }


    public List<Task> list(TaskSelector selector) {
        if (Objects.equals(1, selector.getMine())) {
            selector.getTarget().setOwnerId(SecurityUtils.loginedUserId());
        } else if (Objects.equals(0, selector.getMine())) {
            selector.setOwnerIdNot(SecurityUtils.loginedUserId());
        }
        List<Task> list = taskMapper.select(selector);
        if (list.size() > 0) {
            if (Objects.equals(1, selector.getWithLogList())) {
                TaskLogSelector logSelector = new TaskLogSelector();
                logSelector.setTaskIdList(list.stream().map(x -> x.getId()).distinct().collect(Collectors.toList()));
                List<TaskLog> logList = taskLogService.list(logSelector);
                if (logList.size() > 0) {
                    for (Task task : list) {
                        task.setLogList(logList.stream().filter(x -> Objects.equals(task.getId(), x.getTaskId())).collect(Collectors.toList()));
                    }
                }
            }
            if (Objects.equals(1, selector.getWithPrettyActor())) {
                List<Long> userIdList = new ArrayList<>();
                for (Task task : list) {
                    appendIf(userIdList, task.getOwnerId());
                    appendIf(userIdList, task.getHungBy());
                    appendIf(userIdList, task.getCommittedBy());
                    appendIf(userIdList, task.getApprovedBy());
                    appendIf(userIdList, task.getCreatedBy());
                }
                userIdList = userIdList.stream().distinct().collect(Collectors.toList());
                UserSelector userSelector = new UserSelector();
                userSelector.setIdList(userIdList);
                List<User> userList0 = userService.list(userSelector);
                List<PrettyUser> userList = userList0.stream().map(x -> PrettyUser.build(x)).collect(Collectors.toList());
                for (Task task : list) {
                    task.setCreatedByUser(findIf(userList, task.getCreatedBy()));
                    task.setUpdatedByUser(findIf(userList, task.getUpdatedBy()));
                    task.setCommittedByUser(findIf(userList, task.getCommittedBy()));
                    task.setOwnerUser(findIf(userList, task.getOwnerId()));
                }
            }

            for (Task task : list) {
                if (task.getPlannedCompletionTime() != null && task.getPlannedCompletionTime() > 0) {
                    long today = DateUtils.localDate2Long(LocalDate.now());
                    int d = (int) ((task.getPlannedCompletionTime() - today) / (1000 * 3600 * 24) + 1);
                    task.setDayRemaining(d);
                }
            }
        }
        return list;
    }

    void appendIf(List<Long> list, Long id) {
        if (id != null) list.add(id);
    }

    PrettyUser findIf(List<PrettyUser> list, Long id) {
        if (id == null) return null;
        return list.stream().filter(x -> Objects.equals(x.getId(), id)).findAny().orElse(null);
    }

    public int count(TaskSelector selector) {
        if (Objects.equals(1, selector.getMine())) {
            selector.getTarget().setOwnerId(SecurityUtils.loginedUserId());
        } else if (Objects.equals(0, selector.getMine())) {
            selector.setOwnerIdNot(SecurityUtils.loginedUserId());
        }
        return taskMapper.count(selector);
    }

    public int update(Task issue) {
        long now = System.currentTimeMillis();
        issue.setUpdatedAt(now);
        Long userId = SecurityUtils.loginedUserId();
        issue.setUpdatedBy(userId);
        if (issue.getNewDayRemaining() != null) {
            issue.setDayRemaining(issue.getNewDayRemaining());
            if (Objects.equals(1, issue.getDayRemaining())) {
                long t = DateUtils.localDate2Long(LocalDate.now());
                issue.setPlannedCompletionTime(t);
            } else if (Objects.equals(2, issue.getDayRemaining())) {
                long t = DateUtils.localDate2Long(LocalDate.now().plusDays(1));
                issue.setPlannedCompletionTime(t);
            } else if (Objects.equals(3, issue.getDayRemaining())) {
                long t = DateUtils.localDate2Long(LocalDate.now().plusDays(2));
                issue.setPlannedCompletionTime(t);
            } else if (issue.getDayRemaining() > 3) {
                long t = DateUtils.localDate2Long(LocalDate.now().plusDays(issue.getDayRemaining() - 1));
                issue.setPlannedCompletionTime(t);
            }
        }

        if (issue.getId() == null || issue.isNewEntity() || issue.getId() <= 0L) {
            if (userId == null) {
                MyBaseException.throwMe(10401, "未登录");
            }
            if (issue.getId() == null || issue.getId() <= 0L) {
                issue.setId(idService.nextId());
            }
            if (issue.getOwnerId() == null) {
                MyBaseException.throwMe(10401, "用户未指定");
            }
            if (issue.getIssueId() == null) {
                MyBaseException.throwMe(10401, "Issue未指定");
            }
            issue.setCreatedAt(now);
            issue.setCreatedBy(userId);
            taskMapper.insert(issue);
        }
        return taskMapper.update(issue);
    }

    public int log(Long taskId, String type) {
        long now = System.currentTimeMillis();
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) return -1;
        Task task = get(taskId);
        if (task == null) return -1;
        TaskLog taskLog = new TaskLog();
        taskLog.setIssueId(task.getIssueId());
        taskLog.setTaskId(task.getId());
        taskLog.setType(type);
        taskLog.setOwnerId(userId);
        taskLog.setStartAt(now);
        TaskLog prev = null;
        if ("start".equalsIgnoreCase(type)) {
            task.setStartAt(now);
            task.setStatus(1);
            //其他任务要关闭
            TaskLogSelector logSelector = new TaskLogSelector();
            logSelector.getTarget().setOwnerId(taskLog.getOwnerId());
            logSelector.getTarget().setType("start");
            logSelector.setOrderBy("id desc");
            logSelector.setPageSize(1);
            prev = taskLogService.list(logSelector).stream().findAny().orElse(null);
            if (prev != null) {
                if (prev.getEndAt() == null) {
                    prev.setEndAt(now);
                } else {
                    prev = null;
                }
            }

        } else if ("stop".equalsIgnoreCase(type)) {
//            WorkLog workLog = new WorkLog();
//            workLog.setOwnerId(userId);
//            workLog.setBusinessDate(DateUtils.localDate2Long(LocalDate.now()));
//            workLog.setTaskId(task.getId());
//            workLog.setSubject(task.getSubject());
//            workLog.setIssueId(task.getIssueId());
//            workLog.setType("task");
//            workLog.setDuration(task.getTime());
//            workLog.setStartAt(System.currentTimeMillis());
//            workLogService.update(workLog);
        }
        TaskLog prev2 = prev;
        int r = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                update(task);
                if (prev2 != null) {
                    taskLogService.update(prev2);
                }
                //
                return taskLogService.update(taskLog);
            }
        });
//        if ("start".equalsIgnoreCase(type)) {
//            WorkLog workLog = new WorkLog();
//            workLog.setOwnerId(userId);
//            workLog.setBusinessDate(DateUtils.localDate2Long(LocalDate.now()));
//            workLog.setTaskId(task.getId());
//            workLog.setSubject(task.getSubject());
//            workLog.setIssueId(task.getIssueId());
//            workLog.setType("task");
//            workLog.setDuration(task.getTime());
//            workLog.setStartAt(System.currentTimeMillis());
//            workLogService.update(workLog);
//        }
        return r;
    }

    public int hang(Long taskId, Integer hung, String reason) {
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) {
            MyBaseException.throwMe(10401, "未登录");
        }
        Task task = get(taskId);
        if (task == null) return -1;

        return hang(task, hung, reason);
    }

    public int hang(Task task, Integer hung, String reason) {
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) {
            MyBaseException.throwMe(10401, "未登录");
        }

        long now = System.currentTimeMillis();

        if (task == null) return -1;
        if (Objects.equals(1, hung)) {
            task.setHung(1);
            task.setHungAt(now);
            task.setHungBy(userId);
            task.setHungReason(reason);
        } else {
            task.setHung(0);
            task.setHungAt(0L);
            task.setHungBy(0L);
            task.setHungReason(reason);

        }
        return update(task);
    }

    public int commit(Long taskId, Integer commited) {
        return commit(get(taskId), commited);
    }

    public int commit(Task task, Integer commited) {
        if (task == null) {
            return 0;
        }
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) {
            MyBaseException.throwMe(10401, "未登录");
        }
        long now = System.currentTimeMillis();
        if (task == null) return -1;
        //if (Objects.equals(1, task.getHung())) return 0;
        TaskLog log = new TaskLog();
        log.setOwnerId(userId);
        log.setTaskId(task.getId());
        log.setIssueId(task.getIssueId());

        if (Objects.equals(1, commited)) {
            task.setCommitted(1);
            task.setCommittedAt(now);
            task.setCommittedBy(userId);
            task.setStatus(4);
            task.setProgress(100);
            log.setType("commit");
        } else {
            task.setCommitted(0);
            task.setCommittedAt(0L);
            task.setCommittedBy(0L);
            log.setType("uncommit");
            task.setStatus(1);
        }
        //Issue issue = issueService.get(task.getIssueId());
        int r = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                taskLogService.update(log);
                int r = update(task);
                if (Objects.equals(1, task.getCommitted())) {
                    issueService.commit(task.getIssueId(), commited);
                }
                return r;
            }
        });
        return r;
    }

    public int approve(Long taskId, Integer approved) {
        return approve(get(taskId), approved);
    }

    public int approve(Task task, Integer approved) {
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) {
            MyBaseException.throwMe(10401, "未登录");
        }
        long now = System.currentTimeMillis();
        if (task == null) return -1;
        if (Objects.equals(1, task.getHung())) return 0;
        TaskLog log = new TaskLog();
        log.setOwnerId(userId);
        log.setTaskId(task.getId());
        log.setIssueId(task.getIssueId());

        if (Objects.equals(1, approved)) {
            task.setApproved(1);
            task.setApprovedAt(now);
            task.setApprovedBy(userId);

            log.setType("approve");
        } else if (Objects.equals(-1, approved)) {
            task.setApproved(0);
            task.setApprovedAt(0L);
            task.setApprovedBy(0L);
            log.setType("disapprove");
        } else {
            task.setApproved(0);
            task.setApprovedAt(0L);
            task.setApprovedBy(0L);
            log.setType("disapprove");
        }
        int r = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                taskLogService.update(log);
                return update(task);
            }
        });
        return r;
    }


    public int giveup(Long taskId, Integer giveup, String reason) {
        return giveup(get(taskId), giveup, reason);
    }

    public int giveup(Task task, Integer giveup, String reason) {
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) {
            MyBaseException.throwMe(10401, "未登录");
        }
        long now = System.currentTimeMillis();
        if (task == null) return -1;
        if (Objects.equals(1, task.getHung())) return 0;

        if (Objects.equals(1, giveup)) {
            task.setGiveup(1);
            task.setGiveupAt(now);
            task.setGiveupBy(userId);
        } else {
            task.setGiveup(0);
            task.setGiveupAt(0L);
            task.setGiveupBy(0L);
        }
        int r = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {

                return update(task);
            }
        });
        return r;
    }

    public int dependent(Long taskId, Integer dependent, String reason) {
        return dependent(get(taskId), dependent, reason);
    }

    public int dependent(Task task, Integer dependent, String reason) {
        Long userId = SecurityUtils.loginedUserId();
        if (userId == null) {
            MyBaseException.throwMe(10401, "未登录");
        }
        long now = System.currentTimeMillis();
        if (task == null) return -1;
        Issue issue = issueService.get(task.getIssueId());
        if (issue == null) return -1;

        task.setDependent(dependent);
        issue.setDependent(dependent);
        int r = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus status) {
                issueService.update(issue);
                return update(task);
            }
        });
        return r;
    }


}
